Station Smart Contract Wallet

Context

Meridian Impact Evaluator payments into Station wallets have a fundamental problem: Every transfer incurs gas fees, which would have to be paid by PL. This both causes unnecessary cost (Station operators don’t need to use their funds every IE round, so most transfers are wasted) and opens an attack vector (funds can be drained by inflating the participant count).

Proposal

This document is proposing a shift in Station wallet architecture, towards a more smart contract based model. The IE smart contract now holds participants’ balances, and Station operators withdraw on demand. PL doesn’t need to pay gas for reward each IE round any more, yet Station operators can still withdraw for free, through a new sponsored withdrawal service (which subtracts gas cost to fund itself). Through this, the intermediary Station Wallet doesn’t need to hold any balance any more, and can simply function as an identity provider for withdrawing and in general interacting with the smart contract.

💡
Funds will be transferred directly from the IE smart contract into the destination wallet, which is not the Station wallet any more.

Changes

Smart Contract

  • add state
    mapping(address => uint) balances
  • add function
    getBalance() public view returns uint
    • return state
  • add function
    transfer(address target, uint amount) public
    • support f4/0x addresses
    • support f1 addresses
    • update state (optional gc)
    • transfer funds
    • emit event Transfer(address indexed from, address to, uint amount)
  • add function
    transferOnBehalf(address participant, bytes signature, address target, uint amount) public
    • verify signature check(signature, from, to, amount)
    • send 0.1FIL (adjustable) back to sender, to pay for gas
    • transfer() with different participant address and 0.1FIL deducted
  • change function
    reward(address[] addresses, uint[] scores) private
    • update state

Station Desktop

  • update onboarding text
  • update empty wallet text
FunctionBeforeAfter
Show balancethis.signer.getBalance()contract.getBalance()
Withdraw FIL (sponsored)this.signer.sendTransaction(to, amount)fetch(transferAPI, {
body: JSON.stringify({
from,
signature,
to,
amount
})
}
List transactionsfetch('https://filfox.info/.../${address})contract.filters.Transfer(signer.address)
The wallet history will be changed to withdrawal history, as funds theoretically come in every 30m (or as configured), which would just bloat the list
💡
We have removed filfox.info, thereby not relying on a centralized service any more, plus removing a hefty unsolved requirement from the upcoming IPC integration

Station Core

  • When operators supply their Station Desktop address as FIL_WALLET_ADDRESS, they can use Station Desktop to withdraw (sponsored). This is the suggested flow.
  • Operators can withdraw manually by direct contract interaction or using the unsponsored transfer web UI (coming later, see below)

Sponsored transfer service

  • Bootstrap web service with wallet
  • Add route POST /transfer
    • read { from, signature, to, amount }
    • verify signature check(signature, from, to, amount)
    • acquire mutex lock on from address
    • call contract.balances(from) to verify balance > 0.1 FIL
    • call contract.transferFor(from, signature, to, amount)
      • contract sends amount - 0.1FIL to to
      • contract sends 0.1FIL back, to pay for gas
      • amount deducted can be tweaked
    • await tx confirmed
    • release mutex lock on from address

Unsponsored transfer

  • Participants may withdraw anytime by calling contract.transfer(target, amount)
  • The Station team might eventually provide a web UI for this, just like Saturn did.

Future

This change aligns us more closely with ERC20 token contracts, and the way of operating in an L2 IPC subnet (where you also withdraw on demand). Therefore, it both fixes a current flaw as well as aligning us better with upcoming architectural changes.

Resourcing

@Julian Gruber can work on this mostly independently, assuming code reviews from @Miroslav Bajtoš.

Timeline

Until LabWeek 2023, Nov 13th.

A very basic version of the flow can be implemented in 1d, the rest of time is spent making it stable and polished.

Known problems

  • It’s possible to add unlimited participants to the balances mapping, as we’re sponsoring the measurement and evaluate service gas, allowing participants to introduce new addresses without paying for it. I anticipate that the requirement of performing non-fraudulent Spark work in order to get added to the balances mapping is enough of a hurdle to prevent unbound growth.